use crate::utils;

use super::config::mongo_connection::Connection;
use bson::doc;
use log::{error, info};
use r2d2_mongodb::mongodb::coll::options::{FindOneAndUpdateOptions, FindOptions, ReturnDocument};
use r2d2_mongodb::mongodb::db::ThreadedDatabase;
use r2d2_mongodb::mongodb::Error;
use rocket::serde;

pub type MongoDbConn = Connection;

impl MongoDbConn {
    /// 查询一条数据
    pub fn find_one<T>(
        &self,
        coll_name: &str,
        filter: Option<bson::Document>,
        options: Option<FindOptions>,
    ) -> Result<Option<T>, Error>
    where
        T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug,
    {
        info!(
            "mongodb['find_one']执行语句,filter={:?},options={:?}",
            filter, options
        );
        let result = self.0.collection(coll_name).find_one(filter, options);
        match result {
            Ok(doc) => match doc {
                Some(doc) => match bson::from_bson::<T>(bson::Bson::Document(doc)) {
                    Ok(stu) => Ok(Some(stu)),
                    Err(e) => {
                        error!("数据转换失败, {:?}", e);
                        return Err(Error::DefaultError(format!("数据转换失败,{:?}", e)));
                    }
                },
                None => Ok(None),
            },
            Err(e) => return Err(Error::DefaultError(format!("数据库查询失败,{:?}", e))),
        }
    }

    /// 更新数据
    pub fn update<T>(
        &self,
        coll_name: &str,
        filter: bson::Document,
        update: bson::Document,
        options: Option<FindOneAndUpdateOptions>,
    ) -> Result<Option<T>, Error>
    where
        T: serde::Serialize + serde::de::DeserializeOwned + std::fmt::Debug,
    {
        let mut update_data = update;
        let date = bson::Bson::I64(utils::date_time::timestamp());
        update_data.insert("updateTime", date);

        let mut update = doc! {};
        update.insert("$set", update_data);

        info!(
            "mongodb['find_one_and_update']执行语句,filter={:?},update={:?},options={:?}",
            filter, update, options
        );
        let mut opt = options
            .clone()
            .unwrap_or(FindOneAndUpdateOptions::default());
        opt.return_document = Some(ReturnDocument::After);

        let result = self
            .0
            .collection(coll_name)
            .find_one_and_update(filter, update, Some(opt));
        match result {
            Ok(doc) => match doc {
                Some(doc) => match bson::from_bson::<T>(bson::Bson::Document(doc)) {
                    Ok(stu) => Ok(Some(stu)),
                    Err(e) => {
                        error!("数据转换失败, {:?}", e);
                        return Err(Error::DefaultError(format!("数据转换失败,{:?}", e)));
                    }
                },
                None => Ok(None),
            },
            Err(e) => {
                error!("cuowu {:?}", e);
                return Err(Error::DefaultError(format!("修改失败,{:?}", e)));
            }
        }
    }
}
